/*
 *
 *  *    Copyright 2020-2021 Luter.me
 *  *
 *  *    Licensed under the Apache License, Version 2.0 (the "License");
 *  *    you may not use this file except in compliance with the License.
 *  *    You may obtain a copy of the License at
 *  *
 *  *      http://www.apache.org/licenses/LICENSE-2.0
 *  *
 *  *    Unless required by applicable law or agreed to in writing, software
 *  *    distributed under the License is distributed on an "AS IS" BASIS,
 *  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  *    See the License for the specific language governing permissions and
 *  *    limitations under the License.
 *
 */

package com.luter.heimdall.core.config;

import com.luter.heimdall.core.config.options.ResolveTokenOptions;
import com.luter.heimdall.core.config.options.SameSiteOptions;
import com.luter.heimdall.core.config.options.TokenTypeOptions;
import lombok.Data;

import java.time.Duration;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * 全局参数配置
 *
 * @author luter
 */
@Data
public class HeimdallProperties {

    /**
     * The Token.
     */
    private TokenProperty token = new TokenProperty();
    /**
     * Cookie 参数
     */
    private CookieProperty cookie = new CookieProperty();
    /**
     * The Authority.
     */
    private AuthorityProperty authority = new AuthorityProperty();

    /**
     * The Jwt.
     */
    private JwtProperty jwt = new JwtProperty();

    /**
     * 重试次数限制器
     */
    private LimiterProperty limiter = new LimiterProperty();
    /**
     * The Scheduler.
     */
    private SchedulerProperty scheduler = new SchedulerProperty();

    /**
     * The type Token property.
     *
     * @author luter
     */
    @Data
    public static class TokenProperty {
        /**
         * Token 模式，Session+cookie 或者 Jwt
         */
        private TokenTypeOptions type = TokenTypeOptions.SESSION;
        /**
         * token 的，请求参数名称
         */
        private String name = "HeToken";
        /**
         * Token 签发人，默认:luter
         */
        private String iss = "luter";
        /**
         * 如何从请求参数中解析 token,默认：ALL。
         */
        private ResolveTokenOptions tokenFrom = ResolveTokenOptions.ALL;
        /**
         * 请求中 token value 的前缀
         */
        private String tokenPrefix = "";
        /**
         * Token 在缓存中 key 的前缀,默认:heimdall:tokens:
         */
        private String cachePrefix = "heimdall:tokens:";
        /**
         * token 超时时间,单位：秒,默认:3600
         */
        private long timeout = Duration.ofHours(1).getSeconds();
        /**
         * 最大允许登录次数，<=-1 :不限制,0:禁止登录.默认：1
         */
        private int maximumTokens = 1;
        /**
         * 超过登录次数后限制的行为.true :抛出异常，拒绝登录.false:踢出前面登录，执行本次登录。默认:false
         */
        private boolean maxTokensPreventLogin = false;
        /**
         * 剩余时长占总时长比例低于多少(0.01-0.99)开始续签，默认:0.5,数字越大续签越频繁
         */
        private double ratio = 0.5;
        /**
         * 是否开启 token 续签，默认：关闭
         */
        private boolean renewal = false;
    }

    /**
     * The type Cookie property.
     *
     * @author luter
     */
    @Data
    public static class CookieProperty {
        /**
         * 是否开启 cookie 功能，默认:开启
         */
        private boolean enabled = true;
        /**
         * The Domain.
         */
        private String domain = "";
        /**
         * Cookie 生命周期,-1:永久,默认：3600 ，单位：秒
         */
        private Integer maxAge = 3600;
        /**
         * The Path.
         */
        private String path = "/";
        /**
         * The Secure.
         */
        private Boolean secure = false;
        /**
         * The Http only.
         */
        private Boolean httpOnly = true;
        /**
         * The Same site.
         */
        private SameSiteOptions sameSite = SameSiteOptions.LAX;
    }

    /**
     * The type Jwt.
     *
     * @author luter
     */
    @Data
    public static class JwtProperty {
        /**
         * 是否开启白名单
         */
        private boolean whiteList = false;
        /**
         * jwt Secret秘钥
         */
        private String secret = "aaasdas123123*^*&^*&12312312asd";
    }

    /**
     * 权限配置
     *
     * @author luter
     */
    @Data
    public static class AuthorityProperty {
        /**
         * 开启认证授权过滤器,默认:开启.
         */
        private boolean enabled = true;
        /**
         * 拦截规则。满足这些规则，会被授权拦截
         */
        private List<String> includes = Collections.singletonList("/**");
        /**
         * 排除规则，满足这些规则将不会被授权拦截
         */
        private List<String> excludes = Arrays.asList("/static/**",
                "/images/**",
                "/css/**",
                "/js/**",
                "/favicon*",
                "/error");
        /**
         * 系统权限在缓存中的key
         */
        private String appCacheKeyPrefix = "heimdall:appperms";
        /**
         * 系统权限在缓存中保存的时长。单位:秒.默认 :24小时
         */
        private long appCacheExpire = Duration.ofDays(1).getSeconds();
        /**
         * 用户权限在缓存中的key
         */
        private String userCacheKeyPrefix = "heimdall:userperms";
        /**
         * 用户权限在缓存中保存的时长。单位:秒.默认 :12小时
         */
        private long userCacheExpire = Duration.ofHours(12).getSeconds();
    }

    /**
     * The type Limiter property.
     *
     * @author luter
     */
    @Data
    public static class LimiterProperty {
        /**
         * 是否开启重试限制,默认开启
         */
        private boolean enabled = true;
        /**
         * 允许重试的最大次数,attempts+1请求会被拒绝，默认：3，最少 3 次
         */
        private int attempts = 3;
        /**
         * key在缓存中的前缀，默认:"heimdall:retryLimit:"
         */
        private String cachePrefix = "heimdall:limiter:";
        /**
         * 锁定时长,单位：分钟,默认:2，最少 1 分钟
         */
        private long lockedDuration = 2;
    }

    /**
     * The type Scheduler property.
     *
     * @author luter
     */
    @Data
    public static class SchedulerProperty {
        /**
         * 是否开启过期 Token定时清理任务，默认：未开启
         */
        private boolean tokenEnabled = false;
        /**
         * 是否开启过期 权限 定时清理任务，默认：未开启
         */
        private boolean authorityEnabled = false;
        /**
         * 过期 Token 缓存清理任务在系统启动后多少秒后开始定时任务,默认:600秒,最少60秒
         */
        private long initialDelay = 600;
        /**
         * Token 缓存 清理任务每隔多少秒执行一次定时任务,默认:一小时，最少600秒
         */
        private long tokenPeriod = Duration.ofHours(1).getSeconds();
        /**
         * 权限缓存 清理任务每隔多少秒执行一次定时任务,默认：一天
         */
        private long authorityPeriod = Duration.ofDays(1).getSeconds();
    }

}
